﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace SuperX.SuperSocket.Socket.Transfer.Server
{
    public class FileTransferServerEngine : IDisposable
    {
        internal AutoResetEvent m_EndEvent = new AutoResetEvent(false);
        internal AutoResetEvent m_StopEvent = new AutoResetEvent(false);
        internal object lockobj = new object();
        internal FileStream m_fileStream;
        internal FileInfo UpLoadInfo;
        internal FileInfo DownloadInfo;
        internal object downloadLockobj = new object();

        public event TransferEventHandler<TransferStepEventArgs> TransferStep;

        public event TransferEventHandler<TransferCompleteEventArgs> TransferComplete;

        public event TransferEventHandler<StartTransferEventArgs> StartTransfer;

        public event TransferEventHandler<StopTransferEventArgs> StopTransfer;

        //internal Dictionary<string, int> DownloadStatusCodes = new Dictionary<string, int>();
        private TransferSession Session;

        private Timer _timeoutTimer;
        public int TimeoutCount { get; set; } = 10000; //毫秒

        public FileTransferServerEngine(TransferSession session)
        {
            Session = session;
        }

        internal void OnTransferStep(long _TotalLen, long _TransferLen, int _CurrentPacket)
        {
            _timeoutTimer?.Change(TimeoutCount, Timeout.Infinite);
            if (TransferStep != null)
            {
                TransferStep(new TransferStepEventArgs(
                    UpLoadInfo == null ? DownloadInfo.ProjectId : UpLoadInfo.ProjectId,
                    _TotalLen, _TransferLen, _CurrentPacket));
            }
        }

        internal void OnTransferComplete(TransferCompleteEventArgs eventArgs)
        {
            if (TransferComplete != null)
                TransferComplete(eventArgs);
        }

        internal void OnStartTransfer(FileInfo upLoadConfigInfo)
        {
            _timeoutTimer = new Timer(TimerCallback, null, TimeoutCount, Timeout.Infinite);
            if (StartTransfer != null)
            {
                StartTransfer(new StartTransferEventArgs(upLoadConfigInfo.ProjectId,
                    upLoadConfigInfo.FileName, upLoadConfigInfo.SaveName,
                    upLoadConfigInfo.FileSize, upLoadConfigInfo.TransferPos,
                    upLoadConfigInfo.TransferLength));
            }
        }

        private void TimerCallback(object state)
        {
            var message = string.Format("传输文件超时{0}毫秒", TimeoutCount);
            ConsoleLogHelper.Warn(message + Environment.NewLine + new StackTrace().ToString());
            Dispose();
        }

        internal void OnStopTransfer(StopTransferEventArgs eventArgs)
        {
            if (StopTransfer != null)
                StopTransfer(eventArgs);
        }

        internal void SendData(UpLoadOP opCode, byte[] data, int offset, int length)
        {
            byte[] dst = new byte[length + 4];
            dst[0] = (byte)((int)opCode / 256);
            dst[1] = (byte)((int)opCode % 256);
            dst[2] = (byte)(length / 256);
            dst[3] = (byte)(length % 256);
            Buffer.BlockCopy(data, offset, dst, 4, length);
            Session.Send(dst, 0, dst.Length);
        }

        internal void DoUploadEnd()
        {
            m_fileStream.Close();
            string saveName = Path.GetFullPath(UpLoadInfo.SaveName);
            string saveTempName = saveName + Config.TempSuffix;
            string configName = saveName + Config.ConfigSuffix;
            ConsoleLogHelper.Debug("server doend");
            File.Move(saveTempName, saveName);
            if (File.Exists(configName))
            {
                File.Delete(configName);
            }

            SendData(UpLoadOP.DoCheckServerComplete, new byte[] { 1 }, 0, 1);
            OnTransferComplete(new TransferCompleteEventArgs(UpLoadInfo.ProjectId));
            Dispose();
        }

        internal void DoDownloadEnd()
        {
            m_fileStream.Close();
            if (DownloadInfo.DownloadAutoDelFile && File.Exists(DownloadInfo.FileName))
            {
                var fileDir = Path.GetDirectoryName(DownloadInfo.FileName);
                Directory.Delete(fileDir, true);
            }
            ConsoleLogHelper.Debug("server do download end");
            OnTransferComplete(new TransferCompleteEventArgs(DownloadInfo.ProjectId));
            Dispose();
        }

        internal void DoUpLoad(FileInfo ClientConfigInfo)
        {
            string saveName = Path.GetFullPath(ClientConfigInfo.SaveName);
            string saveTempName = saveName + Config.TempSuffix;
            FileInfo ServerConfigInfo = null;
            string configName = ClientConfigInfo.SaveName + Config.ConfigSuffix;
            string saveNamePath = Path.GetDirectoryName(saveName);
            if (!Directory.Exists(saveNamePath))
                Directory.CreateDirectory(saveNamePath);
            if (File.Exists(saveTempName))
            {
                m_fileStream = new FileStream(saveTempName, FileMode.Open, FileAccess.Write);
                if (File.Exists(configName))
                {
                    ServerConfigInfo = SerializeHelp.DeserializeFromFile<FileInfo>(configName);
                }
            }
            else
            {
                m_fileStream = new FileStream(saveTempName, FileMode.Create, FileAccess.Write);
                m_fileStream.SetLength(ClientConfigInfo.FileSize);
            }
            if (ServerConfigInfo == null)
            {
                ServerConfigInfo = ClientConfigInfo;
                SerializeHelp.SerializeToFile<FileInfo>(ServerConfigInfo, configName);
            }
            //如果客户端传来的已上传大小与服务端的已上传大小不一致
            //if(ServerConfigInfo.TransferedLength!= ClientConfigInfo.TransferedLength)
            //{
            //}
            //如果客户端传来的文件大小与服务端的文件大小不一致
            //to do something
            UpLoadInfo = ServerConfigInfo;
            m_fileStream.Position = ServerConfigInfo.TransferPos + ServerConfigInfo.TransferedLength;
            byte[] data = SerializeHelp.Serialize<FileInfo>(ServerConfigInfo);
            SendData(UpLoadOP.DoUpLoad, data, 0, data.Length);
        }

        public void Dispose()
        {
            //Logger.Warn("Dispose" + Environment.NewLine + new StackTrace().ToString());
            if (Session?.TransferServer?.ServerUploadState?.SessionID == Session?.SessionID)
            {
                Session?.TransferServer.ServerUploadState.ReleaseLock();//释放上传的锁
            }
            _timeoutTimer?.Dispose();
            _timeoutTimer = null;
            if (m_EndEvent != null)
            {
                m_EndEvent.Reset();
                m_EndEvent = null;
            }
            if (m_fileStream != null)
            {
                m_fileStream.Close();
                m_fileStream = null;
            }
            if (UpLoadInfo != null)
                UpLoadInfo = null;
            if (TransferStep != null)
                TransferStep = null;
            if (TransferComplete != null)
                TransferComplete = null;
            if (StartTransfer != null)
                StartTransfer = null;
            if (StopTransfer != null)
                StopTransfer = null;
            if (Session != null)
            {
                Session.Close();
                Session = null;
            }
        }
    }
}